function [ U, S, V, output ] = APGLog( O, lambda, para )

expc = 5;
rho = 0.5*expc^2;

X0 = zeros(size(O));
X1 = X0;
Omega = (O > 0);

maxIter = para.maxIter;
tol = para.tol;

obj = zeros(maxIter, 1);
RMSE = zeros(maxIter, 1);
Time = zeros(maxIter, 1);
t = tic;
c = 1;
for i = 1:maxIter 
    Xi = X1 + (c - 1)/(c + 2) * (X1 - X0);
    Z = Xi - (1/rho)*gradLog(Xi, O, expc).*Omega;
    % Z = Xi - (Xi.*Omega - O.*Omega);
    % choose SVD type
    [ U, S, V ] = proximalOperator( Z, lambda/rho);
    
    Xi = U*S*V';
    
    X0 = X1;
    X1 = Xi;
    
    % check objective value  
    temp = logLoss( Xi(:), O(:), expc);
    temp = temp.*Omega(:);
    temp = sum(temp);
    obj(i) = temp + lambda*sum(S(:));
    
    if(i > 1)
        delta = obj(i - 1) - obj(i);
    else
        delta = inf;
    end
    
    
    if(isfield(para, 'test'))
        RMSE(i) = TestError(Xi, para.test.row, para.test.col, para.test.data);
        fprintf('Testing RMSE %d \n', RMSE(i));
    end
    
    % testing peformance
    Time(i) = toc(t);
    fprintf('iter %d, (obj:%.3d, tol:%.3d), rank:%d, lambda %.2d \n', ...
        i, obj(i), delta, nnz(S), lambda);
    
    if(delta < 0)
        c = 1;
    else
        c = c + 1;
        
        if(abs(delta) < tol)
            break;
        end
    end
end

output.rank = nnz(S);
output.obj = obj(1:i);
output.RMSE = RMSE(1:i);
output.Time = Time(1:i);

end

%% ------------------------------------------------------------------------
function [G] = gradLog(X, O, c)

e1 = exp(c*(  X - O - 0.5));
e2 = exp(c*(- X + O - 0.5));
G = c*(e1./( 1 + e1) - e2./(1 + e2));

% G = X - O;

end
